package tld.course.lesson2 
{
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.ui.Keyboard;
	import flash.utils.Timer;
	
	[SWF(width="600", height="620")]
	
	/**
	 * HOMEWORK:
	 * - Make snake move twice as fast.
	 * - Add new kind of food, which is added once per every 20 regular food, 
	 * 	 this kind of food would give you extra `lives' (would instead reduce
	 * 	 the lenght of the snake).
	 * - Make speed of the snake increase over the time, each time it `eats',
	 * 	 the speed would grow by 1% of the base speed.
	 * - Reverse the control (the down button should tell the snake to move up,
	 * 	 the up button should tell the snake to move down).
	 * - BONUS: Localize the game to Russian or Hebrew.
	 * @author wvxvw
	 */
	public class SnakeGame extends Sprite
	{
		private static const NORTH:uint = 1;
		private static const EAST:uint = 5;
		private static const SOUTH:uint = 7;
		private static const WEST:uint = 3;
		private static const DINNER_TIME:uint = 10;
		
		private const _timer:Timer = new Timer(100);
		private const _score:TextField = new TextField();
		private const _reset:Sprite = new Sprite();
		private const _format:TextFormat = new TextFormat("_sans");
		
		private var _grid:Grid;
		private var _canvas:Canvas;
		private var _snake:Snake;
		private var _direction:uint;
		private var _timeSinceLastDinner:uint;
		
		public function SnakeGame() 
		{
			super();
			this.init();
		}
		
		private function init(event:Event = null):void
		{
			this._format.align = TextFormatAlign.CENTER;
			this._canvas = new Canvas(super.graphics);
			this._canvas.snake = 
				this._snake = 
				new Snake(Math.random() * 100, Math.random() * 100);
			this._canvas.grid = this._grid = new Grid(100, 100);
			this._canvas.update(this.calculateCellSize());
			super.stage.addEventListener(
				KeyboardEvent.KEY_DOWN, this.keyDownHandler);
			this._timer.addEventListener(TimerEvent.TIMER, this.timerHandler);
			this._score.width = 300;
			this._score.height = 20;
			this._score.y = 600;
			this._score.defaultTextFormat = this._format;
			super.addChild(this._score);
			this._timer.start();
			this.drawButton();
		}
		
		private function timerHandler(event:TimerEvent):void
		{
			var cellValue:uint;
			var nextX:int = this._snake.headX + (this._direction % 3) - 1;
			var nextY:int = this._snake.headY + (this._direction / 3) - 1;
			
			if (this._direction)
			{
				if (this._grid.canMove(nextX, nextY))
				{
					cellValue = this._grid.get(nextX, nextY);
					this._snake.move(this._direction, Boolean(cellValue));
					if (!cellValue)
						this._grid.set(this._snake.lastX, this._snake.lastY, 0);
					else this._score.text = 
						this.generatePoints(this._snake.length - 1);
					this._grid.set(nextX, nextY, 1);
					this._canvas.update(this.calculateCellSize());
					if (this._timeSinceLastDinner == DINNER_TIME)
					{
						this._grid.serveFood(2);
						this._timeSinceLastDinner = 0;
					}
					else this._timeSinceLastDinner++;
				}
				else
				{
					this._score.text = "You loose!";
					this._direction = 0;
					this._timer.stop();
				}
			}
		}
		
		private function generatePoints(points:uint):String
		{
			var result:String = " point";
			if (points % 10 != 1) result += "s";
			return points + result + ".";
		}
		
		private function calculateCellSize():uint
		{
			return Math.min(super.stage.stageWidth, 
				super.stage.stageHeight) / 100;
		}
		
		private function keyDownHandler(event:KeyboardEvent):void
		{
			var desired:uint;
			
			switch (event.keyCode)
			{
				case Keyboard.UP:
					desired = NORTH;
					break;
				case Keyboard.DOWN:
					desired = SOUTH;
					break;
				case Keyboard.LEFT:
					desired = WEST;
					break;
				case Keyboard.RIGHT:
					desired = EAST;
					break;
			}
			if (!this.isOppositeDirection(this._direction, desired))
				this._direction = desired;
		}
		
		private function isOppositeDirection(previous:uint, desired:uint):Boolean
		{
			var result:Boolean;
			
			switch (previous)
			{
				case NORTH:
					result = desired == SOUTH;
					break;
				case SOUTH:
					result = desired == NORTH;
					break;
				case WEST:
					result = desired == EAST;
					break;
				case EAST:
					result = desired == WEST;
					break;
			}
			return result;
		}
		
		private function drawButton():void
		{
			var canvas:Graphics = this._reset.graphics;
			var label:TextField;
			if (!this._reset.width)
			{
				canvas.beginFill(0xF0F0F0);
				canvas.drawRect(0, 0, 300, 20);
				canvas.endFill();
				label = this._reset.addChild(new TextField()) as TextField;
				label.width = this._reset.width;
				label.height = this._reset.height;
				label.defaultTextFormat = this._format;
				label.text = "Reset!";
				label.selectable = false;
				super.addChild(this._reset);
				this._reset.y = 600;
				this._reset.x = 300;
				this._reset.addEventListener(MouseEvent.CLICK, this.init);
			}
		}
	}
}